-- cache tempalte
-- this is provided as a guide to build your cache. It is by no means unfallable.
-- you may need to update vector bit ranges to match specifications in lab handout.
--
-- THIS IS NOT ERROR FREE CODE, YOU MUST UPDATE AND VERIFY SANITY OF LOGIC/INTERFACES
--

library ieee;
use ieee.std_logic_1164.all;

entity cache_top is
  port(
    CLK       : in  std_logic;
    nReset    : in  std_logic;

		Halt			:	in	std_logic;											 -- CPU side
    MemRead		: in  std_logic;                       -- CPU side
		MemWrite	:	in	std_logic;											 -- CPU side
    MemWait		: out std_logic;                       -- CPU side
    MemAddr		: in  std_logic_vector (31 downto 0);  -- CPU side
    MemRdData	: out	std_logic_vector (31 downto 0);  -- CPU side
    MemWrData	: in	std_logic_vector (31 downto 0);  -- CPU side

    aMemWait	: in  std_logic;                       -- arbitrator side
		aMemState	: in	std_logic_vector (1 downto 0);	 -- arbitrator side
    aMemRead	: out std_logic;                       -- arbitrator side
    aMemWrite	: out std_logic;                       -- arbitrator side
    aMemAddr	: out std_logic_vector (31 downto 0);  -- arbitrator side
    aMemData	: in  std_logic_vector (31 downto 0)   -- arbitrator side
	);
end cache_top;

architecture struct of cache_top is
	component cache
		port (
			CLK					: in 	std_logic;
			nReset			:	in 	std_logic;
			WrEn				: in	std_logic;
			Tag					:	in 	std_logic_vector(24 downto 0);
			Index				: in	std_logic_vector(3 downto 0);
			CacheBlockI	: in 	std_logic_vector(63 downto 0);
			CacheBlockO	: out	std_logic_vector(63 downto 0);
			Dirty				:	out	std_logic;
			Hit					: out	std_logic
		);
	end component;

	component cache_ctrl
		port (
			CLK					: in	std_logic;
			nReset			: in	std_logic;
			Hit					: in	std_logic;
			Read				:	in	std_logic;
			Write				:	in	std_logic;
			RamWait			: in	std_logic;
			RamState		: in	std_logic_vector(1 downto 0);
			BlockAddr		:	in	std_logic_vector(28 downto 0);
			Word				:	in	std_logic_vector(31 downto 0);
			BlockDirty	:	in	std_logic;
			CacheBlockI	:	in	std_logic_vector(63 downto 0);
			CacheBlockO	:	out	std_logic_vector(63 downto 0);
			WordAddr		:	out	std_logic_vector(31 downto 0);
			RamRead			:	out	std_logic;
			RamWrite		:	out	std_logic;
			WrEn				:	out	std_logic
		);
	end component;

	-- internal singals
	signal tWrEn, tHit, tDirty					: std_logic; 
	signal tUpdatedBlock, tCacheBlock		: std_logic_vector (63 downto 0);

begin

	CACHE: cache port map(
		CLK,
		nReset,
		tWrEn,										-- update data in cache
		MemAddr (31 downto 7),		-- tag to look for
		MemAddr (6 downto 3),			-- set to look in
		tUpdatedBlock,						-- new block to put in cache
		tCacheBlock,							-- cache block from set and selected way
		tDirty,										-- is cache block dirty?
		tHit,											-- did we find a matching cache block
);

	CCTRL: cache_ctrl port map(
		CLK,
		nReset,
		tHit,											-- does the controller need to do anything?
		MemRead,									-- memory write to cache on misss
		MemWrite,									-- cpu write to cache (depends on write policy)
		aMemWait,									-- which cache has control of memory
		aMemState,								-- are we there yet?
		MemAddr (31 downto 3),		-- cache block addr (both words)
		dMemData,									-- word coming from memory
		MemWrData,								-- word coming from CPU
		tDirty,										-- cache block needs to be written to memory
		tCacheBlock,							-- cache block
		tUpdatedBlock,						-- new block with requested data
		aMemAddr,									-- memory address to get word for cache block
		tWrEn);										-- update the cache with new block
		
	-- set memwait
	MemWait <= not tHit;

	-- return word from block 
	with MemAddr(2) select MemData <= 
		tCacheBlock(63 downto 32) when '0'
		tCacheBlock(31 downto 00) when others;	

	-- on halt: flush the cache blocks that are dirty
	-- put that logic here

end struct;
